/*
 * Copyright 2015 泛泛o0之辈
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.jfast.framework.web.api;

import cn.jfast.framework.base.JFastVersion;
import cn.jfast.framework.base.cache.CacheManager;
import cn.jfast.framework.base.prop.PropLoader;
import cn.jfast.framework.base.prop.CoreConsts;
import cn.jfast.framework.base.cache.cacheimpl.ConcurrentMapCacheManager;
import cn.jfast.framework.base.util.Assert;
import cn.jfast.framework.base.util.ClassUtils;
import cn.jfast.framework.base.util.ObjectUtils;
import cn.jfast.framework.base.util.StringUtils;
import cn.jfast.framework.jdbc.annotation.Dao;
import cn.jfast.framework.jdbc.info.Column;
import cn.jfast.framework.jdbc.db.ConnectionFactory;
import cn.jfast.framework.jdbc.db.DBProp;
import cn.jfast.framework.jdbc.info.Table;
import cn.jfast.framework.jdbc.orm.DaoProxy;
import cn.jfast.framework.log.LogFactory;
import cn.jfast.framework.log.LogType;
import cn.jfast.framework.log.Logger;
import cn.jfast.framework.schedule.ScheduleExecuter;
import cn.jfast.framework.schedule.ScheduledJob;
import cn.jfast.framework.web.validate.ValidateHandler;
import cn.jfast.framework.web.annotation.*;
import cn.jfast.framework.base.cache.Cache;
import cn.jfast.framework.web.aop.AopScope;
import cn.jfast.framework.web.aop.AopHandler;
import cn.jfast.framework.web.annotation.Aop;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

public class ApiContext {

	private static Logger log = LogFactory.getLogger(LogType.JFast,
			ApiContext.class);

	public static CacheManager cacheManager = new ConcurrentMapCacheManager();

	private static PropLoader loader = new PropLoader();

	public static int APP_HOST_PATH_LENGTH;

	public static Map<String, String> staticResourceMap;

	private static boolean isInit = false;

	private static Set<String> apiToken = new HashSet<String>();

	public static void loadContext() {
		if (!isInit) {
			isInit = true;
			if (isInit) {
				synchronized (loader) {
					loadConfig();
					logSysInfo();
					loadDBInfo();
					loadCache();
				}
			}
		}
	}

	public static void loadDBInfo() {
		if (StringUtils.isNotBlank(DBProp.jdbc_driver)
				&& StringUtils.isNotBlank(DBProp.jdbc_password)
				&& StringUtils.isNotBlank(DBProp.jdbc_url)
				&& StringUtils.isNotBlank(DBProp.jdbc_user)) {
			try {
				Connection conn = ConnectionFactory.getThreadLocalConnection();
				DatabaseMetaData meta = conn.getMetaData();
				DBProp.DB_NAME = meta.getDatabaseProductName();
				DBProp.DB_VERSION = meta.getDatabaseProductVersion();
				DBProp.DB_DRIVER = meta.getDriverVersion();
				DBProp.DB_DRIVER = meta.getDriverVersion();
				log.info("[jfast-%s] load database information---- %s",
						JFastVersion.version(), "success");
				log.info("[jfast-%s] database name ---- %s",
						JFastVersion.version(), DBProp.DB_NAME);
				log.info("[jfast-%s] database version ---- %s",
						JFastVersion.version(), DBProp.DB_VERSION);
				log.info("[jfast-%s] database driver ---- %s",
						JFastVersion.version(), DBProp.DB_DRIVER);
				ResultSet rt = meta.getTables(null, null, "%%",
						new String[] { "TABLE" });
				Table table;
				while (rt.next()) {
					table = new Table();
					table.setCatalog(rt.getString("TABLE_CAT"));
					table.setDbName(rt.getString("TABLE_NAME").toLowerCase());
					table.setNickName(StringUtils.dbColumn2ModelColumn(rt
							.getString("TABLE_NAME").toLowerCase()));
					table.setType(rt.getString("TABLE_TYPE"));
					table.setSchema(rt.getString("TABLE_SCHEM"));
					table.setRemarks(rt.getString("REMARKS"));
					ResultSet rc = meta.getColumns(null, null,
							table.getDbName(), "%%");
					Column column;
					while (rc.next()) {
						column = new Column();
						column.setName(rc.getString("COLUMN_NAME")
								.toLowerCase());
						column.setType(rc.getInt("DATA_TYPE"));
						column.setAutoIncrement(rc
								.getString("IS_AUTOINCREMENT"));
						column.setDefaultValue(rc.getString("COLUMN_DEF"));
						column.setSize(rc.getString("COLUMN_SIZE"));
						column.setNullAble(rc.getString("NULLABLE"));
						column.setRemarks(rc.getString("REMARKS"));
						table.addColumn(column);
					}
					ResultSet rp = meta.getPrimaryKeys(null, null,
							table.getDbName());
					while (rp.next()) {
						table.addPrimaryKey(StringUtils.dbColumn2ModelColumn(rp
								.getString("COLUMN_NAME")));
					}
					DBProp.tableCache.put(table.getNickName(), table);
				}
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (SQLException e) {
				log.error("[jfast-%s] load database information ---- %s",
						JFastVersion.version(), "failure");
			}
		}
	}

	public static void loadConfig() {
		Assert.notNull(loader);
		loader.load();
		staticResourceMap = loader.getResourcesMap();
		Map<String, String> propMap = loader.getPropMap();
		Field field = null;
		try {
			for (Map.Entry<String, String> propKV : propMap.entrySet()) {
				try {
					field = DBProp.class.getField(propKV.getKey());
					field.setAccessible(true);
				} catch (NoSuchFieldException e) {
					try {
						field = CoreConsts.class.getField(propKV.getKey());
						field.setAccessible(true);
					} catch (NoSuchFieldException ex) {
						continue;
					}
				}
				if(field.getType() == Boolean.TYPE || field.getType() == Boolean.class)
					field.set(null, Boolean.parseBoolean(propKV.getValue()));
				else if(field.getType() == Integer.TYPE || field.getType() == Integer.class)
					field.set(null, Integer.parseInt(propKV.getValue()));
				else
					field.set(null, propKV.getValue());
			}
			Set<Class<?>> configList = ClassUtils
					.scanClasses(cn.jfast.framework.web.annotation.Config.class);
			synchronized (configList) {
				for (Class<?> clazz : configList) {
					Field[] fields = clazz.getFields();
					for(Field f:fields){
						// 必须是 public static 字段才可以赋值
						if((f.getModifiers() & 0x00000008) != 0 && propMap.containsKey(f.getName())){
							f.setAccessible(true);
							if(f.getType() == Boolean.TYPE || f.getType() == Boolean.class)
								f.set(null, Boolean.parseBoolean(propMap.get(f.getName())));
							else if(field.getType() == Integer.TYPE || field.getType() == Integer.class)
								f.set(null, Integer.parseInt(propMap.get(f.getName())));
							else if(field.getType() == Double.TYPE || field.getType() == Double.class)
								f.set(null, Double.parseDouble(propMap.get(f.getName())));
							else if(field.getType() == Long.TYPE || field.getType() == Long.class)
								f.set(null, Long.parseLong(propMap.get(f.getName())));
							else if(field.getType() == Float.TYPE || field.getType() == Float.class)
								f.set(null, Float.parseFloat(propMap.get(f.getName())));
							else
								f.set(null, propMap.get(f.getName()));
						}
					}
				}
			}
		} catch (Exception e) {
			log.error("", e);
		}
	}

	private static void logSysInfo() {
		log.info("[jfast-%s] java.version ---- %s", JFastVersion.version(),
				CoreConsts.javaVersion);
		log.info("[jfast-%s] java.home ---- %s", JFastVersion.version(),
				CoreConsts.javaHome);
		log.info("[jfast-%s] java.class.version ---- %s",
				JFastVersion.version(), CoreConsts.javaClassVersion);
		log.info("[jfast-%s] os.name ---- %s", JFastVersion.version(),
				CoreConsts.osName);
		log.info("[jfast-%s] os.arch ---- %s", JFastVersion.version(),
				CoreConsts.osArch);
		log.info("[jfast-%s] os.version ---- %s", JFastVersion.version(),
				CoreConsts.osVersion);
		log.info("[jfast-%s] user.name ---- %s", JFastVersion.version(),
				CoreConsts.userName);
		log.info("[jfast-%s] user.home ---- %s", JFastVersion.version(),
				CoreConsts.userHome);
		log.info("[jfast-%s] user.dir---- %s", JFastVersion.version(),
				CoreConsts.userDir);
		log.info("[jfast-%s] host.ip ---- %s", JFastVersion.version(),
				CoreConsts.hostIP);
		log.info("[jfast-%s] host.name ---- %s", JFastVersion.version(),
				CoreConsts.hostName);
	}

	private static void loadCache() {
		loadTableNameCache();
		loadDaoCache();
		loadResourceCache();
		loadInterceptorCache();
		loadValidateCache();
		loadApiCache();
		loadScheduleJobCache();
	}

	public synchronized static void loadTableNameCache() {
		DBProp.modelCache.clear();
		Set<Class<?>> tableList = ClassUtils
				.scanClasses(cn.jfast.framework.jdbc.annotation.Table.class);
		synchronized (tableList) {
			for (Class<?> clazz : tableList) {
				cn.jfast.framework.jdbc.annotation.Table model = clazz
						.getAnnotation(cn.jfast.framework.jdbc.annotation.Table.class);
				String alias = StringUtils.dbColumn2ModelColumn(model.value());
				Assert.isFalse(DBProp.modelCache.containsKey(alias),
						"repeat msg table name [ " + alias + " ]");
				DBProp.modelCache.put(clazz.getSimpleName().toLowerCase(),
						alias);
			}
		}
	}

	private synchronized static void loadValidateCache() {
		Cache validateCache = cacheManager.getCache("validate");
		validateCache.clear();
		Set<Class<?>> validateList = ClassUtils
				.scanClasses(cn.jfast.framework.web.annotation.Validate.class);
		synchronized (validateList) {
			for (Class<?> clazz : validateList) {
				cn.jfast.framework.web.annotation.Validate validate = clazz
						.getAnnotation(cn.jfast.framework.web.annotation.Validate.class);
				String alias = validate.name();
				Assert.isFalse(validateCache.containsKey(alias),
						"repeat validate name [ " + alias + " ]");
				log.info(
						"[jfast-%s] load validate ---- alias : %s | target : %s | description: %s",
						JFastVersion.version(), alias, clazz.getSimpleName(),
						validate.description());
				validateCache.put(alias, clazz);
			}
		}
	}

	public synchronized static void loadResourceCache() {
		Cache resourceCache = cacheManager.getCache("resource");
		resourceCache.clear();
		Cache daoCache = cacheManager.getCache("dao");
		Set<Class<?>> resourceList = ClassUtils.scanClasses(Resource.class);
		synchronized (resourceCache) {
			for (Class<?> clazz : resourceList) {
				Resource resource = clazz.getAnnotation(Resource.class);
				String alias = "".equals(resource.name()) ? StringUtils
						.firstCharToLowerCase(clazz.getSimpleName()) : resource
						.name();
				Assert.isFalse(daoCache.containsKey(alias),
						"repeat dao or resource name [ " + alias + " ]");
				Assert.isFalse(resourceCache.containsKey(alias),
						"repeat dao or resource name  [ " + alias + " ]");
				log.info(
						"[jfast-%s] load resource ---- alias : %s | target : %s | description: %s",
						JFastVersion.version(), alias, clazz.getSimpleName(),
						resource.description());
				resourceCache.put(alias, clazz);
			}
		}
	}

	public synchronized static void loadDaoCache() {
		Cache daoCache = cacheManager.getCache("dao");
		daoCache.clear();
		Cache resourceCache = cacheManager.getCache("resource");
		Set<Class<?>> daoList = ClassUtils.scanClasses(Dao.class);
		synchronized (daoCache) {
			for (Class<?> clazz : daoList) {
				Dao dao = clazz.getAnnotation(Dao.class);
				String alias = "".equals(dao.name()) ? StringUtils
						.firstCharToLowerCase(clazz.getSimpleName()) : dao
						.name();
				Assert.isNull(daoCache.get(alias),
						"repeat dao or resource name [ " + alias + " ]");
				Assert.isNull(resourceCache.get(alias),
						"repeat dao or resource name [ " + alias + " ]");
				log.info(
						"[jfast-%s] load dao ---- alias: %s | target : %s | description: %s",
						JFastVersion.version(), alias, clazz.getSimpleName(),
						dao.description());
				daoCache.put(alias, clazz);
			}
		}
	}

	@SuppressWarnings("unchecked")
	private synchronized static void loadApiCache() {
		Cache apiCache = cacheManager.getCache("api");
		apiCache.clear();
		Set<Class<?>> actionList = ClassUtils
				.scanClasses(cn.jfast.framework.web.annotation.Api.class);
		String typeRoute;
		String methodRoute;
		String description;
		HttpMethod apiMethod;
		Class<?> api;
		List<Class<? extends AopHandler>> methodAops;
		final List<Class<? extends AopHandler>> globalAops = new ArrayList<Class<? extends AopHandler>>(
				0);
		Map<Object, Object> cache = cacheManager.getCache("aop")
				.getNativeCache();
		for (Object obj : cache.values())
			globalAops.add((Class<? extends AopHandler>) obj);
		for (Class<?> clazz : actionList) {
			api = clazz;
			typeRoute = clazz.getAnnotation(
					cn.jfast.framework.web.annotation.Api.class).path();
			for (Method method : clazz.getMethods()) {
				methodAops = new ArrayList<Class<? extends AopHandler>>(0);
				if (method.isAnnotationPresent(Aop.class)) {
					methodAops.addAll(Arrays.asList(method.getAnnotation(
							Aop.class).handler()));
					methodAops.remove(AopHandler.class);
				}
				if (method.isAnnotationPresent(Put.class)) {
					methodRoute = method.getAnnotation(Put.class).path();
					description = method.getAnnotation(Put.class).description();
					apiMethod = HttpMethod.PUT;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Get.class)) {
					methodRoute = method.getAnnotation(Get.class).path();
					description = method.getAnnotation(Get.class).description();
					apiMethod = HttpMethod.GET;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Post.class)) {
					methodRoute = method.getAnnotation(Post.class).path();
					description = method.getAnnotation(Post.class)
							.description();
					apiMethod = HttpMethod.POST;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Delete.class)) {
					methodRoute = method.getAnnotation(Delete.class).path();
					description = method.getAnnotation(Delete.class)
							.description();
					apiMethod = HttpMethod.DELETE;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Search.class)) {
					methodRoute = method.getAnnotation(Search.class).path();
					description = method.getAnnotation(Search.class)
							.description();
					apiMethod = HttpMethod.SEARCH;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Options.class)) {
					methodRoute = method.getAnnotation(Options.class).path();
					description = method.getAnnotation(Options.class)
							.description();
					apiMethod = HttpMethod.OPTIONS;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Head.class)) {
					methodRoute = method.getAnnotation(Head.class).path();
					description = method.getAnnotation(Head.class)
							.description();
					apiMethod = HttpMethod.HEAD;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Trace.class)) {
					methodRoute = method.getAnnotation(Trace.class).path();
					description = method.getAnnotation(Trace.class)
							.description();
					apiMethod = HttpMethod.TRACE;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Patch.class)) {
					methodRoute = method.getAnnotation(Patch.class).path();
					description = method.getAnnotation(Patch.class)
							.description();
					apiMethod = HttpMethod.PATCH;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Move.class)) {
					methodRoute = method.getAnnotation(Move.class).path();
					description = method.getAnnotation(Move.class)
							.description();
					apiMethod = HttpMethod.MOVE;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Mkcol.class)) {
					methodRoute = method.getAnnotation(Mkcol.class).path();
					description = method.getAnnotation(Mkcol.class)
							.description();
					apiMethod = HttpMethod.MKCOL;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Connect.class)) {
					methodRoute = method.getAnnotation(Connect.class).path();
					description = method.getAnnotation(Connect.class)
							.description();
					apiMethod = HttpMethod.CONNECT;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Copy.class)) {
					methodRoute = method.getAnnotation(Copy.class).path();
					description = method.getAnnotation(Copy.class)
							.description();
					apiMethod = HttpMethod.COPY;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Lock.class)) {
					methodRoute = method.getAnnotation(Lock.class).path();
					description = method.getAnnotation(Lock.class)
							.description();
					apiMethod = HttpMethod.LOCK;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Unlock.class)) {
					methodRoute = method.getAnnotation(Unlock.class).value();
					description = method.getAnnotation(Unlock.class)
							.description();
					apiMethod = HttpMethod.UNLOCK;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Proppatch.class)) {
					methodRoute = method.getAnnotation(Proppatch.class).path();
					description = method.getAnnotation(Proppatch.class)
							.description();
					apiMethod = HttpMethod.PROPPATCH;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				} else if (method.isAnnotationPresent(Propfind.class)) {
					methodRoute = method.getAnnotation(Propfind.class).path();
					description = method.getAnnotation(Propfind.class)
							.description();
					apiMethod = HttpMethod.PROPFIND;
					addApi(typeRoute, methodRoute, api, method, apiMethod,
							methodAops, globalAops, apiCache, description);
				}
			}
		}
	}

	private static synchronized void addApi(String typeRoute,
			String methodRoute, Class<?> api, Method method,
			HttpMethod apiMethod, List<Class<? extends AopHandler>> methodAops,
			List<Class<? extends AopHandler>> globalAops, Cache apiCache,
			String description) {
		Api action = new Api(typeRoute.trim(), methodRoute.trim(), api, method,
				apiMethod, methodAops, globalAops);
		Assert.isFalse(apiCache.containsKey(action.getCacheUri()),
				"repeat api name [ " + action.getApiUri() + " ]");
		log.info(
				"[jfast-%s] load api ---- path: %s | target: %s | description: %s",
				JFastVersion.version(), action.getApiUri(), api.getSimpleName()
						+ "." + method.getName() + "()", description);
		apiCache.put(action.getCacheUri(), action);
		apiToken.addAll(Arrays.asList(action.getCacheUri().split("/")));
	}

	private synchronized static void loadInterceptorCache() {
		Cache aopCache = cacheManager.getCache("aop");
		aopCache.clear();
		Set<Class<?>> aops = ClassUtils.scanClasses(Aop.class);
		for (Class<?> clazz : aops) {
			if (AopHandler.class.isAssignableFrom(clazz)) {
				if (clazz.isAnnotationPresent(Aop.class)) {
					Aop aop = clazz.getAnnotation(Aop.class);
					if (aop.scope() == AopScope.Method)
						continue;
					String alias = StringUtils.isEmpty(aop.alias()) ? StringUtils
							.firstCharToLowerCase(clazz.getSimpleName()) : aop
							.alias();
					Assert.isFalse(aopCache.containsKey(alias),
							"repeat aop name [ " + alias + " ]");
					log.info(
							"[jfast-%s] load aop ---- alias : %s | target : %s | description: %s",
							JFastVersion.version(), alias,
							clazz.getSimpleName(), aop.description());
					aopCache.put(alias, clazz);
				}
			} else {
				throw new RuntimeException("[jfast-%s] load aop error: class "
						+ clazz.getSimpleName() + " must extends AopHandler");
			}
		}
	}

	private static void loadScheduleJobCache() {
		Cache jobCache = cacheManager.getCache("job");
		jobCache.clear();
		Set<Class<?>> jobList = ClassUtils
				.scanClasses(cn.jfast.framework.web.annotation.Job.class);
		String jobStr;
		Object obj = null;
		for (Class<?> jobClass : jobList) {
			try {
				obj = jobClass.newInstance();
				obj = fillResource(obj);
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
			for (Method method : jobClass.getMethods()) {
				Schedule schedule = method.getAnnotation(Schedule.class);
				if (null != schedule) {
					if(!schedule.enable())
						continue;
					ScheduledJob job = new ScheduledJob(obj, method,
							schedule.cron(), schedule.delay(),
							schedule.repeat(), schedule.repeatInterval());
					jobStr = StringUtils.firstCharToLowerCase(jobClass
							.getName() + "." + method.getName());
					log.info(
							"[jfast-%s] load schedule job ---- target : %s | description: %s",
							JFastVersion.version(), jobClass.getName() + "."
									+ method.getName() + "()",
							schedule.description());
					jobCache.put(jobStr, job);
				}
			}
		}
		ScheduleExecuter.me().initService(jobCache).start();
	}

	public static boolean handlerResources(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		String route = getResourceRoute(request);
		for (String resourceRoute : staticResourceMap.keySet()) {
			if (route.startsWith(resourceRoute)
					&& !route.startsWith(staticResourceMap.get(resourceRoute))) {
				request.getRequestDispatcher(
						route.replaceFirst(resourceRoute,
								staticResourceMap.get(resourceRoute))).forward(
						request, response);
				return true;
			}
		}
		return false;
	}

	public static boolean handlerApi(HttpRequest request, HttpResponse response)
			throws ServletException, IOException {
		String route = getApiRoute(request);
		ApiInvocation invoke = null;
		Api api = getApi(route + "/$" + request.getMethod().toLowerCase() + "$");
		if (null == api) {
			return false;
		}
		try {
			invoke = new ApiInvocation(api, api.getApi().newInstance(),
					request, response, route + "/$"
							+ request.getMethod().toLowerCase() + "$");
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		invoke.invoke();
		return true;

	}

	public static Object getDao(String dao) {
		Object obj = null;
		try {
			Class<?> clazz = (Class<?>) cacheManager.getCache("dao").get(dao);
			if (null != clazz)
				obj = new DaoProxy().getInstance((clazz).newInstance());
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return obj;
	}

	public static Object getResource(String resource) {
		Object obj = null;
		try {
			Class<?> clazz = (Class<?>) cacheManager.getCache("resource").get(
					resource);
			if (null != clazz)
				obj = clazz.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return obj;
	}

	@SuppressWarnings("unchecked")
	public static Api getApi(String reqRoute) {
		Api api;
		Cache apiCache = cacheManager.getCache("api");
		reqRoute = reqRoute.replaceAll("/+", "/");
		api = apiCache.get(reqRoute, Api.class);
		if (ObjectUtils.isNull(api)) {
			Cache methodMappedCache = cacheManager.getCache(StringUtils
					.substringBetween(reqRoute, "$", "$"));
			String commonRoute = Api.commonPathFilter(reqRoute.substring(0,
					reqRoute.indexOf("$")));
			String[] routeToken = commonRoute.split("/");
			List<String> lengthMappedList = methodMappedCache.get(
					routeToken.length, List.class);
			if (null != lengthMappedList) {
				CacheLoop: for (String cacheRoute : lengthMappedList) {
					String[] cacheToken = cacheRoute.substring(1,
							cacheRoute.indexOf("/$")).split("/");
					for (int i = 0; i < routeToken.length; i++) {
						if (!cacheToken[i].equals(routeToken[i])
								&& !cacheToken[i].equals("{}"))
							continue CacheLoop;
					}
					reqRoute = cacheRoute;
				}
			}
			api = apiCache.get(reqRoute, Api.class);
		}
		return api;
	}

	public static Object fillResource(Object object) {
		Class<?> clazz = object.getClass();
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			if (field.isAnnotationPresent(Resource.class)) {
				Resource resource = field.getAnnotation(Resource.class);
				String alias = "".equals(resource.name()) ? StringUtils
						.firstCharToLowerCase(field.getName()) : resource
						.name();
				Object tempObj = getResource(alias);
				if (ObjectUtils.isNull(tempObj))
					tempObj = getDao(alias);
				if (ObjectUtils.isNull(tempObj))
					return object;
				Object resourceObj = fillResource(tempObj);
				try {
					field.set(object, resourceObj);
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}
		return object;
	}

	public void destroy() {
		ScheduleExecuter.me().stop();
		cacheManager.clear();
	}

	private static String getApiRoute(HttpServletRequest request) {
		String uri = request.getRequestURI().substring(
				ApiContext.APP_HOST_PATH_LENGTH);
		if (StringUtils.contains(uri, "."))
			uri = uri.substring(0, uri.indexOf("."));
		return uri;
	}

	private static String getResourceRoute(HttpServletRequest request) {
		return request.getRequestURI().substring(
				ApiContext.APP_HOST_PATH_LENGTH);
	}

	@SuppressWarnings("unchecked")
	public static ValidateHandler getValidate(String validateName)
			throws InstantiationException, IllegalAccessException {
		return ((Class<? extends ValidateHandler>) cacheManager.getCache(
				"validate").get(validateName)).newInstance();
	}

}
